package com.swak.reactivex.threads.waitstrategy;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import com.swak.reactivex.threads.Barrier;
import com.swak.reactivex.threads.WaitStrategy;


@Deprecated
public class LiteTimeoutBlockingWaitStrategy implements WaitStrategy {

	private final Lock lock = new ReentrantLock();
	private final Condition processorNotifyCondition = lock.newCondition();
	private final AtomicBoolean signalNeeded = new AtomicBoolean(false);
	private final long timeoutInNanos;

	public LiteTimeoutBlockingWaitStrategy(final long timeout, final TimeUnit units) {
		timeoutInNanos = units.toNanos(timeout);
	}

	@Override
	public void waitFor(Barrier barrier) throws InterruptedException, TimeoutException {
		long nanos = timeoutInNanos;
		if (!this.checkBarrier(barrier)) {
			lock.lock();
			try {
				while (!this.checkBarrier(barrier)) {
					signalNeeded.getAndSet(true);

					nanos = processorNotifyCondition.awaitNanos(nanos);
					if (nanos <= 0) {
						throw new TimeoutException();
					}
				}
			} finally {
				lock.unlock();
			}
		}

		while (!this.checkBarrier(barrier)) {
			Thread.onSpinWait();
		}
	}

	@Override
	public void wakeup() {
		if (signalNeeded.getAndSet(false)) {
			lock.lock();
			try {
				processorNotifyCondition.signalAll();
			} finally {
				lock.unlock();
			}
		}

	}

}
